package com.design.paystyle.aspect;

import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.Arrays;

/**
 * 请求日志切面类
 *
 * @author by liuxin
 * @version 0.1
 * @date 2021-11-18 15:22
 */
@Slf4j
@Aspect
@Component
@Order(5)
public class LogAspect {

    /**
     * 开始时间
     */
    ThreadLocal<Long> startTime = new ThreadLocal<>();

    /**
     * 方法切入点
     * 第一个*表示返回类型不限
     * 第二个*表示包下的所有类
     * 第三个*表示所有方法
     * (..)表示参数不限
     */
    @Order(2)
    @Pointcut("execution(public * com.design.paystyle.controller.*.*(..))")
    public void pointCut() {
    }

    /**
     * 注解切入点
     * Order代表优先级，越小优先级越高
     */
    @Pointcut("@annotation(com.design.paystyle.annotation.SysLog)")
    @Order(1)
    public void annotationPoint() {
    }

    @Before(value = "annotationPoint() || pointCut()")
    public void before(JoinPoint joinPoint) {
        log.info("方法执行前执行-------before-----start");
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        log.info("====================================");
        log.info("请求来源=>{}", request.getRemoteAddr());
        log.info("请求URL=>{}", request.getRequestURL());
        log.info("请求方式=>{}", request.getMethod());
        log.info("响应方法=>{}",
                joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        log.info("请求参数=>{}", Arrays.toString(joinPoint.getArgs()));
        log.info("=====================================");
        startTime.set(System.currentTimeMillis());
        log.info("方法执行前执行-------before-----end");
    }

    /**
     * 环绕通知，需要参数的请求
     *
     * @param pjp
     * @param arg
     * @return
     * @throws Exception
     */
    @Around("pointCut() && args(arg)")
    public Object around(ProceedingJoinPoint pjp, String arg) throws Throwable {
        log.info("方法环绕------around-----start");
        log.info("请求参数：{}", arg);
        String result = null;
        Object object = pjp.proceed();
        try {
            result = object.toString() + "aop String";
            log.info("result:{}", result);
        } catch (Throwable e) {
            e.printStackTrace();
        }
        log.info("方法环绕------around-----end");
        return object;
    }

    /**
     * 所有接口
     */
    @Pointcut("within(com.design.paystyle.controller.*Controller)")
    public void after() {
        log.info("方法执行之后执行");
    }

    @AfterReturning(pointcut = "pointCut()", returning = "object")
    public void afterRunning(Object object) {
        log.info("请求执行之后执行-----afterReturning-------start");

        if (startTime.get() == null) {
            startTime.set(System.currentTimeMillis());
        }
        log.info("请求执行耗时：{}", (System.currentTimeMillis() - startTime.get()));
        log.info("返回数据：{}", object);
    }

    @AfterThrowing("within(com.design.paystyle.controller.*Controller)")
    public void aroundThrowing() {
        log.info("请求出现异常执行");
    }
}
